/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

package lime2;
import lights.interfaces.*;

/**
 * Resolver of communication failures. 
 *  
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini 
 */

class FailureR implements Failures, Policies, LimeConstants
{	
 /**
  * Manages the communication failure of a Protocol.
  *  
  * @param p Protocol
  * @param ro involved RemoteOp
  * @param lce LimeCommunicationException
  * @param step of the remote protocol
  */
 static void resolve(Protocol p, RemoteOp ro, LimeCommunicationException lce, int step)
 {
  resolve(p, ro, lce, step, null);	
 }
	
 /**
  * Manages the communication failure of a Protocol.
  *  
  * @param p Protocol
  * @param ro involved RemoteOp
  * @param lce LimeCommunicationException
  * @param step of the remote protocol
  * @param extra additional status information
  */
 static void resolve(Protocol p, RemoteOp ro, LimeCommunicationException lce, int step, Object extra)
 {
  // --------------------------------  
  //  backup tuples (from operation)
  // --------------------------------	
  if 
  ( 
   (p.type == REM_INP_UNI   && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Inp-Uni PassiveOpen 	
   (p.type == REM_INP_MULTI && p.subtype == PASSIVE_OPEN && step == 1) || // Rem-Inp-Multi PassiveOpen
   (p.type == REM_ING_UNI   && p.subtype == PASSIVE_OPEN && step == 1) || // Rem-Ing-Uni PassiveOpen
   (p.type == REM_ING_MULTI && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Ing-Multi PassiveOpen  
   (p.type == REM_OUTG      && p.subtype == OPEN         && step == 1)    // Rem-Outg Open  
  )
  {
   RemTupleOp rto = (RemTupleOp) ro;
   if (rto.tuples != null) if (lce.getFailureType() == TOTAL) { p.ltsm.doWrite(rto.tuples); Protocol.ca.removeHost(rto.target); } 
                           else backup(rto.tuples, rto.target, p.ltsm); 
  }
  else
  // ----------------------------
  //  backup tuples (from event)
  // ---------------------------- 	
  if (p.type == REM_INW && p.subtype == OPEN && step == 1) // Rem-In Open
  {
   RemWeakOp rwo = (RemWeakOp) ro;
   ITuple[] tuples = (rwo.wevent.getTuple() == null ? null : new ITuple[] { rwo.wevent.getTuple() });
   if (tuples != null) if (lce.getFailureType() == TOTAL) { p.ltsm.doWrite(tuples); Protocol.ca.removeHost(rwo.target); }
                       else backup(tuples, rwo.target, p.ltsm);
  } 
  else 
  // -------------------
  //  force termination 	
  // -------------------	
  if 
  (
   (p.type == REM_RDP_UNI       && p.subtype == OPEN         && step == 0) || // Rem-Rdp-Uni Open 	
   (p.type == REM_RDP_MULTI     && p.subtype == OPEN         && step == 0) || // Rem-Rdp-Multi Open
   (p.type == REM_RDG_UNI       && p.subtype == OPEN         && step == 0) || // Rem-Rdg-Uni Open
   (p.type == REM_RDG_UNI       && p.subtype == PASSIVE_OPEN && step == 1) || // Rem-Rdg-Uni PassiveOpen
   (p.type == REM_RDG_MULTI     && p.subtype == OPEN         && step == 0) || // Rem-Rdg-Multi Open  
   (p.type == REM_RDG_MULTI     && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Rdg-Multi PassiveOpen
   (p.type == REM_INP_UNI       && p.subtype == OPEN         && step == 0) || // Rem-Inp-Uni Open 	
   (p.type == REM_INP_MULTI     && p.subtype == OPEN         && step == 0) || // Rem-Inp-Multi Open
   (p.type == REM_INP_MULTI     && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Inp-Multi PassiveOpen
   (p.type == REM_ING_UNI       && p.subtype == OPEN         && step == 0) || // Rem-Ing-Uni Open  
   (p.type == REM_ING_MULTI     && p.subtype == OPEN         && step == 0) || // Rem-Ing-Multi Open 	
   (p.type == REM_OUTG          && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Outg PassiveOpen
   (p.type == REM_INSTALL_UNI   && p.subtype == OPEN         && step == 0) || // Rem-Install-Uni Open  
   (p.type == REM_INSTALL_UNI   && p.subtype == OPEN         && step == 1) || // Rem-Install-Uni Open 
   (p.type == REM_INSTALL_UNI   && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Install-Uni PassiveOpen
   (p.type == REM_INSTALL_MULTI && p.subtype == OPEN         && step == 0) || // Rem-Install-Multi Open
   (p.type == REM_REMOVE_UNI    && p.subtype == OPEN         && step == 0) || // Rem-Remove-Uni Open  
   (p.type == REM_REMOVE_UNI    && p.subtype == OPEN         && step == 1) || // Rem-Remove-Uni Open 	
   (p.type == REM_REMOVE_UNI    && p.subtype == PASSIVE_OPEN && step == 0) || // Rem-Remove-Uni PassiveOpen
   (p.type == REM_REMOVE_MULTI  && p.subtype == OPEN         && step == 0) || // Rem-Remoce-Multi Open
   (p.type == REM_INW           && p.subtype == OPEN         && step == 0) || // Rem-In Open
   (p.type == REM_INW           && p.subtype == PASSIVE_OPEN && step == 0)    // Rem In PassiveOpen
  ) 	
  {
   // .. only if the failure is TOTAL	
   if (lce.getFailureType() == TOTAL) 
   {	
   	// the remote host is declared dead (.. if it is not a multicast communication)
   	if (!((p.type == REM_RDP_MULTI || p.type == REM_RDG_MULTI     || p.type == REM_INP_MULTI    || 
      	   p.type == REM_ING_MULTI || p.type == REM_INSTALL_MULTI || p.type == REM_REMOVE_MULTI ) 
		&& p.subtype == OPEN && step == 0)) Protocol.ca.removeHost(ro.target);
   	// we have to give away the token
   	if (p.type == REM_INW && p.subtype == PASSIVE_OPEN) ((Token) extra).give();
    // != null: PASSIVE_OPEN operations do not synchronize on a result	
    if (p.agent != null) p.agent.lock.release(); 	
    throw new ProtocolTerminationException("protocol terminated", lce);
   } 
  }
  else
  // -----------------------------------	
  //  backup tuples & force termination 
  // -----------------------------------
  if 
  (
   (p.type == REM_OUT  && p.subtype == OPEN && step == 0) || // Rem-Out Open
   (p.type == REM_OUTG && p.subtype == OPEN && step == 0)    // Rem-Outg Open	
  ) 
  {
   // .. only if the failure is TOTAL	
   if (lce.getFailureType() == TOTAL)
   {	
	// the remote host is declared dead
   	Protocol.ca.removeHost(ro.target);	
    ITuple[] tuples = (p.type == REM_OUT ? ((RemTupleOp) ro).tuples : (ITuple[]) extra);
    if (tuples != null) p.ltsm.doWrite(tuples); 
    // we are sure that agent != null: OPEN operations synchronize on a result	
    p.agent.lock.release();	
    throw new ProtocolTerminationException(lce);
   } 
  }
  else
  // -------------------------------
  //  failure within reconciliation 
  // -------------------------------
  if (p.type == RECONCILE) // a failure during any step of a reconciliation process aborts it   
  {
   // the remote host is declared dead
   Protocol.ca.removeHost(ro.target);		
   throw new ProtocolTerminationException(); 	
  }
 }
 
 /**
  * Backup tuples on the basis of the reconciliation policies.
  * 
  * @param tuples to backup
  * @param target to whom tuples were to be sent
  * @param ltsm involved LimeTSMgr
  */
 static void backup(ITuple[] tuples, LimeServerID target, LimeTSMgr ltsm)
 {
  switch (ltsm.getPolicy()) 
  {
   case LOSS:         break;
   case DUPLICATE:    ltsm.doWrite(tuples); break;
   case CONSERVATIVE: GhostBag.addGhostTuples(target, ltsm.getName(), tuples); break;
  } 
 }
 
}
